/*! \file HXShader.h
    \brief GLSL program object wrapper (modification of NVIDIA SDK GLSLProgramObject).

	Head X | Flinders University | Martin Luerssen | 2009+
*/

#pragma once

#define GLEW_STATIC
#include "GL/glew.h"
#include <string>
#include <vector>

using namespace std;

class HXShader
{
public:
	HXShader();
	virtual ~HXShader();

	void Destroy();
	bool Link();
	bool SetUniform(const string& name, GLfloat* val, int count);
	bool SetTextureUnit(const string& texname, int texunit);
	bool BindTexture(GLenum target, const string& texname, GLuint texid, int texunit);
	bool SetFloat(const string& varname, float value);

	// inline:
	bool AttachVertexShaderFromFile(const wstring& filename)
	{
		return AttachShaderFromFile(filename, GL_VERTEX_SHADER, m_vertexShaders);
	}
	bool AttachFragmentShaderFromFile(const wstring& filename)
	{
		return AttachShaderFromFile(filename, GL_FRAGMENT_SHADER, m_fragmentShaders);
	}
	bool AttachVertexShaderFromString(const string& source)
	{
		return AttachShaderFromString(source, GL_VERTEX_SHADER, m_vertexShaders);
	}
	bool AttachFragmentShaderFromString(const string& source)
	{
		return AttachShaderFromString(source, GL_FRAGMENT_SHADER, m_fragmentShaders);
	}
	void Bind()
	{
		glUseProgram(m_progId);
	}
	void Unbind()
	{
		glUseProgram(0);
	}
	bool BindTexture2D(const string& texname, GLuint texid, int texunit) 
	{
		return BindTexture(GL_TEXTURE_2D, texname, texid, texunit);
	}
	bool BindTexture3D(const string& texname, GLuint texid, int texunit) 
	{
		return BindTexture(GL_TEXTURE_3D, texname, texid, texunit);
	}
	bool BindTextureRECT(const string& texname, GLuint texid, int texunit) 
	{
		return BindTexture(GL_TEXTURE_RECTANGLE_ARB, texname, texid, texunit);
	}
	GLuint GetProgId() { return m_progId; }
	
protected:
	GLuint CompileShader(GLenum target, const char* shader);
	bool AttachShaderFromFile(const wstring& filename, GLenum targetId, vector<GLuint>& targetArray);
	bool AttachShaderFromString(const string& source, GLenum targetId, vector<GLuint>& targetArray);

	vector<GLuint>		m_vertexShaders;
	vector<GLuint>		m_fragmentShaders;
	GLuint				m_progId;
};
